package com.example.demo.generator.scaffold.model;

import lombok.Data;

import java.util.List;
import java.util.Objects;

/**
 * 脚手架生成配置项。
 */
public class ScaffoldOptions {

    /**
     * 主键字段名称，默认取第一个字段。
     */
    private String primaryFieldName;

    /**
     * 作者信息，可用于模板注释。
     */
    private String author;

    /**
     * 模块描述，用于注释或文档。
     */
    private String moduleDescription;

    /**
     * 默认 REST 路径前缀。
     */
    private String apiPrefix;

    /**
     * 是否启用区块链模板生成。
     */
    private boolean enableBlockchain;

    private List<ChainField> chainFields = List.of();

    /**
     * 生成项目的数据库预设，默认使用内存 H2。
     */
    private DatabaseType databaseType = DatabaseType.H2;

    /**
     * 自定义数据库连接 URL，优先级最高。
     */
    private String databaseUrl;

    /**
     * 数据库主机，仅在非空且未显式指定 URL 时生效。
     */
    private String databaseHost;

    /**
     * 数据库端口，仅在非空且未显式指定 URL 时生效。
     */
    private Integer databasePort;

    /**
     * 数据库用户名。
     */
    private String databaseUsername;

    /**
     * 数据库密码。
     */
    private String databasePassword;

    /**
     * 数据库名称（或 schema）。
     */
    private String databaseName;

    /**
     * 自定义驱动类，默认根据数据库类型选择。
     */
    private String databaseDriverClassName;

    /**
     * 生成前端模板的框架类型，默认 React。
     */
    private FrontendFramework frontendFramework = FrontendFramework.REACT;

    public ScaffoldOptions() {
    }

    public ScaffoldOptions(String primaryFieldName, String author, String moduleDescription) {
        this.primaryFieldName = primaryFieldName;
        this.author = author;
        this.moduleDescription = moduleDescription;
    }

    public static ScaffoldOptions defaultOptions() {
        return new ScaffoldOptions();
    }

    public String getPrimaryFieldName() {
        return primaryFieldName;
    }

    public void setPrimaryFieldName(String primaryFieldName) {
        this.primaryFieldName = primaryFieldName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getModuleDescription() {
        return moduleDescription;
    }

    public void setModuleDescription(String moduleDescription) {
        this.moduleDescription = moduleDescription;
    }

    public String getApiPrefix() {
        return apiPrefix;
    }

    public void setApiPrefix(String apiPrefix) {
        this.apiPrefix = apiPrefix;
    }

    public boolean isEnableBlockchain() {
        return enableBlockchain;
    }

    public void setEnableBlockchain(boolean enableBlockchain) {
        this.enableBlockchain = enableBlockchain;
    }

    public List<ChainField> getChainFields() {
        return chainFields;
    }

    public void setChainFields(List<ChainField> chainFields) {
        this.chainFields = chainFields != null ? chainFields : List.of();
    }

    public DatabaseType getDatabaseType() {
        return databaseType;
    }

    public void setDatabaseType(DatabaseType databaseType) {
        this.databaseType = databaseType != null ? databaseType : DatabaseType.H2;
    }

    public void setDatabaseType(String databaseType) {
        if (databaseType == null || databaseType.isBlank()) {
            this.databaseType = DatabaseType.H2;
            return;
        }
        try {
            this.databaseType = DatabaseType.valueOf(databaseType.trim().toUpperCase());
        } catch (IllegalArgumentException ex) {
            this.databaseType = DatabaseType.H2;
        }
    }

    public String getDatabaseUrl() {
        return databaseUrl;
    }

    public void setDatabaseUrl(String databaseUrl) {
        this.databaseUrl = blankToNull(databaseUrl);
    }

    public String getDatabaseHost() {
        return databaseHost;
    }

    public void setDatabaseHost(String databaseHost) {
        this.databaseHost = blankToNull(databaseHost);
    }

    public Integer getDatabasePort() {
        return databasePort;
    }

    public void setDatabasePort(Integer databasePort) {
        this.databasePort = databasePort;
    }

    public String getDatabaseUsername() {
        return databaseUsername;
    }

    public void setDatabaseUsername(String databaseUsername) {
        this.databaseUsername = blankToNull(databaseUsername);
    }

    public String getDatabasePassword() {
        return databasePassword;
    }

    public void setDatabasePassword(String databasePassword) {
        this.databasePassword = databasePassword;
    }

    public String getDatabaseName() {
        return databaseName;
    }

    public void setDatabaseName(String databaseName) {
        this.databaseName = blankToNull(databaseName);
    }

    public String getDatabaseDriverClassName() {
        return databaseDriverClassName;
    }

    public void setDatabaseDriverClassName(String databaseDriverClassName) {
        this.databaseDriverClassName = blankToNull(databaseDriverClassName);
    }

    public FrontendFramework getFrontendFramework() {
        return frontendFramework;
    }

    public void setFrontendFramework(FrontendFramework frontendFramework) {
        this.frontendFramework = frontendFramework != null ? frontendFramework : FrontendFramework.REACT;
    }

    public void setFrontendFramework(String frontendFramework) {
        if (frontendFramework == null || frontendFramework.isBlank()) {
            this.frontendFramework = FrontendFramework.REACT;
            return;
        }
        try {
            this.frontendFramework = FrontendFramework.valueOf(frontendFramework.trim().toUpperCase());
        } catch (IllegalArgumentException ex) {
            this.frontendFramework = FrontendFramework.REACT;
        }
    }

    @Data
    public static class ChainField {
        private String columnName;
        private String solidityType;
        private boolean indexed;
    }

    public ScaffoldOptions withPrimaryFieldIfAbsent(String primaryFieldName) {
        if (this.primaryFieldName == null || this.primaryFieldName.isBlank()) {
            this.primaryFieldName = Objects.requireNonNull(primaryFieldName, "primaryFieldName must not be null");
        }
        return this;
    }

    private static String blankToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    public enum DatabaseType {
        H2,
        MYSQL
    }

    public enum FrontendFramework {
        REACT,
        VUE
    }
}
